home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / ge_cool.lha / GE_COOL2.1 / src / Random / Random.C < prev    next >
C/C++ Source or Header  |  1992-04-13  |  9KB  |  225 lines

  1. //
  2. // Copyright (C) 1991 Texas Instruments Incorporated.
  3. //
  4. // Permission is granted to any individual or institution to use, copy, modify,
  5. // and distribute this software, provided that this complete copyright and
  6. // permission notice is maintained, intact, in all copies and supporting
  7. // documentation.
  8. //
  9. // Texas Instruments Incorporated provides this software "as is" without
  10. // express or implied warranty.
  11. //
  12. //
  13. // Created: MBN 10/03/89 -- Initial design and implementation
  14. // Updated: MBN 01/03/90 -- Correctly generate numbers within specified range
  15. // Updated: DLS 03/27/91 -- New lite version
  16. //
  17. // This file contains  member and friend function implementation  code  for the
  18. // CoolRandom  class defined in  the Random.h  header  file.  Where appropriate and
  19. // possible,  interfaces to, and  us  of,  existing   system functions has been
  20. // incorporated. An overview of the structure of the CoolRandom class, along with a
  21. // synopsis of each  member and friend  function, can be  found in the Random.h
  22. // header file.
  23. //
  24.  
  25. #if defined(DOS)
  26. extern "C" {
  27. #include <stdlib.h>                // for srand() and rand()
  28. }
  29. #else
  30. #include <stdlib.h>                // for srand() and rand()
  31. #endif
  32.  
  33. #ifndef RANDOMH                    // If no definition for CoolRandom
  34. #include <cool/Random.h>            // Include the class header
  35. #endif
  36.  
  37.  
  38. // ~CoolRandom -- Destructor for the CoolRandom class (not inline because it's virtual)
  39. // Input:     None
  40. // Output:    None
  41.  
  42. CoolRandom::~CoolRandom () {}
  43.  
  44.  
  45. // CoolRandom -- Constructor for the CoolRandom class with float arguments
  46. // Input:    RNG type, optional seed, lower, and upper limits
  47. // Output:   None
  48.  
  49. CoolRandom::CoolRandom (RNG_TYPE rng, int seed, float lower, float upper){
  50.   this->s = seed;                // Set seed value
  51.   this->l = lower;                // Set lower bound of range
  52.   this->u = upper;                // Set upper bound of range
  53.   this->init (rng);                // Make anti-correlation buffer
  54. }
  55.  
  56.  
  57. // init -- Build the cache of random numbers using the RNG function selected
  58. //         to preclude any correlation of the sequence of numbers generated
  59. // Input:  None
  60. // Output: None
  61.  
  62. void CoolRandom::init (RNG_TYPE rng) {
  63.   unsigned int i = 2;                // Starting value
  64.   unsigned int j = i;                // Temporary
  65.   long mj,mk;                    // Temporaries for Knuth
  66.   do {                        // While still valid bits
  67.     j = i;                    // Set maximum random number
  68.     i <<= 1;                    // Shift left by one bit
  69.   } while (i);                    // Until no more bits left
  70.   this->maxran = j;                // Set maximum number
  71.   switch (rng) {                // Select generator function
  72.   case SIMPLE:
  73.     this->generator = &CoolRandom::simple;        // Set pointer to function
  74.     srand (this->s);                // Set seed value
  75.     break;
  76.  
  77.   case SHUFFLE:                    // Exercise
  78.     this->generator = &CoolRandom::simple;        // Set pointer to function
  79.     srand (this->s);                // Set seed value
  80.     for (i = 0; i < RND_BUF_SIZE; i++)        // Exercise system routine for
  81.       rand ();                    // Small multipliers
  82.     for (i = 0; i < RND_BUF_SIZE; i++)        // Exercise system routine for
  83.       this->buffer[i] = rand ();        // Fill random cache
  84.     this->prev_rnum = rand ();            // Get first value for later
  85.     break;
  86.  
  87.   case ONE_CONGRUENTIAL:
  88.     this->generator = &CoolRandom::one_congruential; // Set pointer to function
  89.     this->ix1 = (INCR-this->s) % MOD;        // Set random seed
  90.     for (i = 1; i < RND_BUF_SIZE; i++) {    // Initialize shuffle table
  91.       this->ix1 = (MULT*this->ix1+INCR)%MOD;    // Calculate random value
  92.       this->buffer[i] = this->ix1;        // And store in random cache
  93.     }
  94.     this->ix1 = (MULT*this->ix1+INCR)%MOD;    // Calculate first value
  95.     this->ix2 = this->ix1;            // Get first value for later
  96.     break;
  97.  
  98.   case THREE_CONGRUENTIAL:
  99.     this->generator = &CoolRandom::three_congruential; // Set pointer to function
  100.     ix1 = (MULT1*((INCR1-this->s)%MOD1)+INCR1)%MOD1; // Seed first generator
  101.     ix2 = ix1 % MOD2;                // Use to seed second gen
  102.     ix1 = (MULT1*ix1+INCR1)%MOD1;        // Calculate again
  103.     ix3 = ix1 % MOD3;                // And use to seed third
  104.     for (i = 1; i < RND_BUF_SIZE; i++) {    // For each cache entry
  105.       ix1 = (MULT1*ix1+INCR1) % MOD1;        // Calculate 1st deviate
  106.       ix2 = (MULT2*ix2+INCR2) % MOD2;        // Calculate 2nd deviate
  107.       this->buffer[i] = (ix1+ix2*RMOD2)*RMOD1;    // Fill random cache
  108.     }
  109.     break;
  110.  
  111.   case SUBTRACTIVE:
  112.     this->generator = &CoolRandom::subtractive;    // Set pointer to function
  113.     mj = (MSEED - this->s) % MBIG;        // Calculate first random num
  114.     this->k_buffer[KNUTH_SPECIAL-1] = mj;    // and copy to knuth buffer[55]
  115.     mk = 1;
  116.     for (i = 1; i <= 54; i++) {            // For remaining elements
  117.       j = (21 * i) % (KNUTH_SPECIAL - 1);    // Calculate random order
  118.       this->k_buffer[j] = mk;            // and use non-random number
  119.       mk = mj - mk;
  120.       if (mk < 0)                // If negative number
  121.     mk += MBIG;                // Add big number and restart
  122.       mj = this->k_buffer[j];            // And calculate new seed
  123.     }
  124.     for (int k = 1; k <= 4; k++)        // Randomize the table by
  125.       for (i = 1; i < KNUTH_SPECIAL; i++) {    // warming up the generator
  126.     this->k_buffer[i] -= this->k_buffer[1+(i+30) % (KNUTH_SPECIAL-1)];
  127.     if (this->k_buffer[i] < 0)        // If negative table entry
  128.       this->k_buffer[i] += MBIG;        // add a very big number
  129.       }
  130.     ix1 = 0;                    // Initialize loop variable
  131.     ix2 = 31;                    // 32 is special; see Knuth
  132.     break;
  133.   }
  134. }
  135.  
  136.  
  137. // simple -- Encapsulated system-supplied random number generator used when
  138. //           speed is the predominant concern. Although sequential correlation
  139. //           of successive random values is still a high probability, this
  140. //           function called from one of the next methods at least corrects for
  141. //           the weakness of many system random generator functions where the
  142. //           value's least significant bits are very often much less random
  143. //           than the most significant bit
  144. // Input:    None
  145. // Output:   Random number
  146.  
  147. double CoolRandom::simple () {
  148.   return ((double(this->l)+((double(rand ())*(this->u-this->l)))/
  149.        (this->maxran+1.0)));
  150. }
  151.  
  152.  
  153. // shuffle -- A shuffle-algorithm random number generator as described in
  154. //            in chapter 7 of "Numerical  Recipes in C". Shuffle uses  the
  155. //            system-supplied rand() function and a shuffling procedure where
  156. //            random numbers are cached in a buffer and selected randomly to
  157. //            break up sequential correlation in the system-supplied function.
  158. // Input:     None
  159. // Output:    Random number
  160.  
  161. double CoolRandom::shuffle () {
  162.   int index = int(1+double(RND_BUF_SIZE)*this->prev_rnum/this->maxran);
  163.   this->prev_rnum = this->buffer[index];    // Get random number from table
  164.   this->buffer[index] = rand ();        // New random table entry 
  165.   return((double(this->l)+(((this->prev_rnum/this->maxran)*(this->u-this->l)))/
  166.       (this->maxran+1.0)));
  167. }
  168.  
  169.  
  170. // one_congruential -- Uses one linear congruential generator instead of the
  171. //                     rand() function to implement an efficient, portable
  172. //                     random number generator that guarantees there is no
  173. //                     sequential correlation between the values returned
  174. // Input:              None
  175. // Output:             Random number
  176.  
  177. double CoolRandom::one_congruential () {
  178.   int index = int(1+(double(RND_BUF_SIZE)*this->ix2)/MOD); // Next index
  179.   this->ix2 = long(this->buffer[index]);    // Get random number from table
  180.   this->ix1 = (MULT * this->ix1 + INCR) % MOD;    // New seed
  181.   this->buffer[index] = this->ix1;        // New random tbale entry
  182.   return (double(this->l)+((((double)this->ix2 / MOD)*(this->u-this->l))));
  183. }
  184.  
  185.  
  186. // three_congruential -- uses three linear congruential generators to implement
  187. //                       a portable random number generator whose period is
  188. //                       essentially infinite and has no sequential correlation
  189. // Input:                None
  190. // Output:               Random number
  191.  
  192. double CoolRandom::three_congruential () {
  193.   this->ix1 = (MULT1 * this->ix1 + INCR1) % MOD1; // Next number for sequence
  194.   this->ix2 = (MULT2 * this->ix2 + INCR2) % MOD2; // Next number for sequence
  195.   this->ix3 = (MULT3 * this->ix3 + INCR3) % MOD3; // Next number for sequence
  196.   int index = int(1+((double(RND_BUF_SIZE)*this->ix3)/MOD3)); // Generate index
  197.   this->prev_rnum = this->buffer[index];    // Get random number from table
  198.   this->buffer[index] = (this->ix1+this->ix2*RMOD2)*RMOD1; // New table entry
  199.   return (double(this->l)+((this->prev_rnum*(this->u-this->l))));
  200. }
  201.  
  202.  
  203. // subtractive -- A portable random number generator as suggested by Knuth in
  204. //                Volume two of "The Art of Computer Programming" that does not
  205. //                use linear congruential generators, but rather an original
  206. //                subtractive method. According to Knuth, any large MBIG and
  207. //                any smaller but still large MSEED can be substituted.
  208. //                However, the value of KNUTH_SPECIAL is, as its name suggests,
  209. //                special!
  210. // Input:         None
  211. // Output:        Random number
  212.  
  213. double CoolRandom::subtractive () {
  214.   long temp;                    // Temporary
  215.   if (++this->ix1 == KNUTH_SPECIAL)        // If at end of table
  216.     this->ix1 = 1;                // Start over
  217.   if (++this->ix2 == KNUTH_SPECIAL)        // If at end of table
  218.     this->ix2 = 1;                // Start over
  219.   temp = this->k_buffer[this->ix1]-this->k_buffer[this->ix2];
  220.   if (temp < 0)                    // If negative result
  221.     temp += MBIG;                // Compensate for range
  222.   this->k_buffer[this->ix1] = temp;        // New table entry
  223.   return (double(this->l)+((temp*FAC*(this->u-this->l))));
  224. }
  225.